package com.mlk.waste.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.mlk.constant.EngConstant;
import com.mlk.core.component.page.Page;
import com.mlk.core.component.page.Pager;
import com.mlk.core.exception.GlobalException;
import com.mlk.core.exception.ParamException;
import com.mlk.core.util.ServerResponse;
import com.mlk.core.util.SessionUtils;
import com.mlk.core.util.validate.ValidateUtils;
import com.mlk.engSystem.constant.SystemParam;
import com.mlk.engSystem.mapper.EngSysEmpMapper;
import com.mlk.engSystem.po.EngSysEmp;
import com.mlk.engSystem.service.EngSysParamService;
import com.mlk.engUser.mapper.EngUserInRemainMapper;
import com.mlk.engUser.mapper.EngUserMapper;
import com.mlk.engUser.po.EngUserInRemain;
import com.mlk.score.mapper.EngInScoreMapper;
import com.mlk.score.po.EngInScore;
import com.mlk.score.strategy.ScoreStrategy;
import com.mlk.stock.mapper.EngStockDetailMapper;
import com.mlk.stock.po.EngStockDetail;
import com.mlk.waste.mapper.EngWasteTypeTreeMapper;
import com.mlk.waste.mapper.EngWasteUserOrderItemMapper;
import com.mlk.waste.mapper.EngWasteUserOrderMapper;
import com.mlk.waste.mapper.EngWasteUserOrderVerifyMapper;
import com.mlk.waste.po.EngWasteTypeTree;
import com.mlk.waste.po.EngWasteUserOrder;
import com.mlk.waste.po.EngWasteUserOrderItem;
import com.mlk.waste.po.EngWasteUserOrderVerify;
import com.mlk.waste.service.EngWasteUserOrderService;
import com.mlk.waste.utils.OrderCodeUtils;
import com.mlk.waste.vo.EngWasteOrderVO;
import com.mlk.waste.vo.EngWasteUserOrderItemVO;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

@Service
public class EngWasteOrderServiceImpl implements EngWasteUserOrderService {

    @Resource
    private EngWasteUserOrderMapper engWasteOrderMapper;

    @Resource
    private EngWasteUserOrderItemMapper engWasteOrderItemMapper;

    @Resource
    private EngSysEmpMapper engSysEmpMapper;

    @Resource
    private EngWasteUserOrderVerifyMapper engWasteUserOrderVerifyMapper;

    @Resource
    private EngUserMapper engUserMapper;

    @Resource
    private ScoreStrategy scoreStrategy;

    @Resource
    private EngInScoreMapper engInScoreMapper;

    @Resource
    private EngUserInRemainMapper engUserInRemainMapper;

    @Resource
    private EngWasteUserOrderMapper engWasteUserOrderMapper;

    @Resource
    private EngStockDetailMapper engStockDetailMapper;

    @Resource
    private EngSysParamService engSysParamService;

    @Resource
    private EngWasteTypeTreeMapper engWasteTypeTreeMapper;

    @Transactional
    @Override
    public ServerResponse addOrder(EngWasteOrderVO vo) {
        // 校验数据的内容,防止出现参数的异常
        ValidateUtils.validate(vo);
        // 处理明细下单
        if(vo.getOrderType()== EngConstant.UserOrderType.DETAIL_ORDER){
            // 需要计算总数
            BigDecimal total = vo.getItems().stream().map(EngWasteUserOrderItem::getTotalNum)
                    .reduce(new BigDecimal(0.00d), (a, b) -> a.add(b));
            vo.setTotalNum(total);
        }

        // 插入订单的主体信息
        vo.setCreateTime(new Date());
        EngWasteUserOrder order = EngWasteUserOrder.builder().build();
        BeanUtils.copyProperties(vo,order);
        // 生成一个订单号
        order.setOrderCode(OrderCodeUtils.generate());
        // 单位的获取问题
        EngWasteTypeTree treePrice = this.engWasteTypeTreeMapper.selectById(order.getWasteType());
        order.setUnit(treePrice.getUnit());
        // 计算真实的单位信息
        order.setDetailUnit(treePrice.getDetailUnit());
        // 真实插入订单的主体信息
        this.engWasteOrderMapper.insert(order);

        // 下面插入详情信息
        if(CollectionUtils.isEmpty(vo.getItems())){
            // 此处为估量下单的内容,就不会出现订单详情的内容...
            return ServerResponse.ok("订单添加成功");
        }

        vo.getItems().stream().forEach(e->{
            e.setOrderCode(order.getOrderCode());
            // 为子项生成订单号,插入数据库之中.
            this.engWasteOrderItemMapper.insert(e);
        });
        return ServerResponse.ok("订单添加成功");
    }

    @Override
    public ServerResponse queryEveryStatusOrder(String openId, Integer type) {

        EngWasteOrderVO orderVO = new EngWasteOrderVO();
        orderVO.setOpenId(openId);
        // 待接单
        if( type == 1){
            orderVO.setStatus(EngConstant.WASTE_ORDER_STATUS.INIT_ORDER);
        }else if(type == 2){ // 待取件
            orderVO.setStatusSql(" in (2,3,4,5) ");
        }else if(type == 3){ // 已完成
            orderVO.setStatus(EngConstant.WASTE_ORDER_STATUS.FINISH_ORDER);
        }
        return ServerResponse.ok(this.engWasteOrderMapper.selectForPage(orderVO));
    }

    @Override
    public ServerResponse cancelOrder(String orderCode) {
        // 取消订单,就是将状态位设置为0这个特别的数字....
        return this.engWasteOrderMapper.updateStatusByOrderCode(orderCode,EngConstant.WASTE_ORDER_STATUS.CANCELED_ORDER) == 0 ?
            ServerResponse.fail("取消失败"):ServerResponse.ok("取消成功");
    }

    /**
     * 查询订单的详情,实际就是查询订单明细的内容
     * @param orderCode
     * @return
     */
    @Override
    public ServerResponse selectOrderDetail(String orderCode) {
        List<EngWasteUserOrderItem> lists = this.engWasteOrderItemMapper.selectList(new EntityWrapper<>(EngWasteUserOrderItem.builder().orderCode(orderCode).build()));
        return ServerResponse.ok(lists);
    }

    /**
     * 业务员抢单内容
     * @param openId
     * @return
     */
    @Override
    public ServerResponse queryAllWaitOrder(String openId) {
        // 根据openid 查询用户的id
        EngSysEmp engSysEmp = this.engSysEmpMapper.selectOne(EngSysEmp.builder().openId(openId).build());

        return ServerResponse.ok(this.engWasteOrderMapper.queryAllWaitOrder(engSysEmp.getId()));
    }

    /**
     * 抢单
     * @param orderCode
     * @return
     */
    @Override
    public ServerResponse manageOrder(String orderCode,String openId) {
        EngWasteUserOrder order = this.engWasteOrderMapper.selectOne(EngWasteUserOrder.builder().orderCode(orderCode).build());
        if(order.getRecOpenId() != null){
            return ServerResponse.fail("该订单已经被抢");
        }

        // 否则 设置当前人的openid
        int count = this.engWasteOrderMapper.setRecOpenId(orderCode,openId,new Date());

        if(count == 0){
            return  ServerResponse.fail("抢单失败");
        }

        count = this.updateOrderStatus(orderCode,EngConstant.WASTE_ORDER_STATUS.RECEIVED_ORDER);
        if(count == 0){
            return  ServerResponse.fail("抢单失败");
        }
        // 修改订单状态
        return ServerResponse.ok("抢单成功");
    }

    @Transactional
    @Override
    public ServerResponse confirmOrder(EngWasteOrderVO vo) {
        // 更新订单的状态
        this.updateOrderStatus(vo.getOrderCode(),EngConstant.WASTE_ORDER_STATUS.PICKED_ORDER);

        // 订单的子项进行修改
        this.engWasteOrderItemMapper.delOrderItemByOrderCode(vo.getOrderCode());
        // 重新添加子项内容
        if(CollectionUtils.isEmpty(vo.getItems())){
            throw new ParamException("订单没有内容,请确认");
        }

        // 校验子项的数据内容
        vo.getItems().stream().forEach(e->{
            // 发现数据没传,直接报告错误..
            ValidateUtils.validate(e);
        });

        // 更新订单的总重量
        BigDecimal totalNum = vo.getItems().stream().map(EngWasteUserOrderItem ::getTotalNum).reduce(new BigDecimal(0.d),(a,b)->{
            return a.add(b);
        });
        this.engWasteOrderMapper.updateOrderTotalNum(vo.getOrderCode(),totalNum);

        // 更新订单的总价钱
        BigDecimal totalPrice = vo.getItems().stream().map(e->{
            return e.getTotalNum().multiply(e.getSinglePrice());
        }).reduce(new BigDecimal(0.d),(a,b)->{
            return a.add(b);
        });

        this.engWasteOrderMapper.updateOrderTotalPrice(vo.getOrderCode(),totalPrice);

        // 下面计算订单子项的内容
        vo.getItems().stream().forEach(e->{
            e.setTotalPrice(e.getSinglePrice().multiply(e.getTotalNum()));
            try {
                e.setOrderCode(vo.getOrderCode());
                this.engWasteOrderItemMapper.insert(e);
            }catch (Exception ex){
                throw new GlobalException("出现错误");
            }
        });

        // 在这里需要增加一个判断,是否需要管理员进行审核
        // 开启了开关,表示需要审核,则流程继续下去.
        // 否则,流程直接业务员确认就好了.
        if(this.engSysParamService.getIntValue(SystemParam.WASTE_ORDER_NEED_CHECK) == 0){
            // 直接将订单状态更新到业务员确认
            this.engWasteUserOrderMapper.updateStatusByOrderCode(vo.getOrderCode(),EngConstant.WASTE_ORDER_STATUS.EMP_CONFIRMED);
        }
        // 批量新增
        return ServerResponse.ok("操作成功");
    }

    @Override
    @Page
    public Pager listPage(EngWasteOrderVO vo) {
        return Pager.adapt(this.engWasteOrderMapper.selectForPage(vo));
    }

    @Page
    @Override
    public Pager listPageItem(EngWasteUserOrderItemVO item) {
        return Pager.adapt(this.engWasteOrderItemMapper.selectByOrderCode(item.getOrderCode()));
    }

    @Override
    public ServerResponse waitPick(String openId) {
        return ServerResponse.ok(this.engWasteOrderMapper.waitPick(openId)) ;
    }

    @Override
    public ServerResponse orderDetails(String orderCode) {
        EngWasteOrderVO engWasteOrderVO = this.engWasteOrderMapper.selectEngWasteUserOrder(orderCode);
        List<EngWasteUserOrderItem> items = this.engWasteOrderItemMapper.selectList(new EntityWrapper<>(EngWasteUserOrderItem.builder().orderCode(orderCode).build()));
       engWasteOrderVO.setItems(items);
       return ServerResponse.ok(engWasteOrderVO);
    }

    /**
     * 获取审核意见
     * @param orderCode
     * @return
     */
    @Override
    public ServerResponse getVerifyAdvice(String orderCode) {
        return ServerResponse.ok(this.engWasteUserOrderVerifyMapper.getVerifyAdviceByOrderCode(orderCode));
    }

    @Override
    @Page
    public Pager getAllFinishedOrder(String openId) {
        EngWasteOrderVO vo = new EngWasteOrderVO();
        vo.setRecOpenId(openId);
        vo.setStatus(EngConstant.WASTE_ORDER_STATUS.FINISH_ORDER);
        return Pager.adapt(this.engWasteOrderMapper.selectForPage(vo));
    }

    @Override
    public ServerResponse getAllVerifyAdvice(String orderCode) {
        return ServerResponse.ok(this.engWasteUserOrderVerifyMapper.selectList(new EntityWrapper<>(EngWasteUserOrderVerify.builder().orderCode(orderCode).build())));
    }

    /**
     * 审核通过,进入业务员确认的状态
     * @param verify
     * @return
     */
    @Override
    @Transactional
    public ServerResponse verifyOk(EngWasteUserOrderVerify verify) {

        int count = this.engWasteOrderMapper.updateOrderStatus(verify.getOrderCode(),EngConstant.WASTE_ORDER_STATUS.EMP_CONFIRMED);
        if(count == 0){
            return ServerResponse.fail("操作失败");
        }

        verify.setCreateTime(new Date());
        verify.setVerifyType(EngConstant.ORDER_VERIFY_TYPE.ok);
        verify.setCreateName(SessionUtils.getUser().getSysUser().getName());
        count = this.engWasteUserOrderVerifyMapper.insert(verify);
        if(count == 0){
            return ServerResponse.fail("操作失败");
        }

        return ServerResponse.ok("操作成功");
    }



    @Override
    @Transactional
    public ServerResponse verifyFail(EngWasteUserOrderVerify verify) {
        int count = this.engWasteOrderMapper.updateOrderStatus(verify.getOrderCode(),EngConstant.WASTE_ORDER_STATUS.REJECT_ORDER);
        if(count == 0){
            return ServerResponse.fail("操作失败");
        }

        verify.setCreateTime(new Date());
        verify.setVerifyType(EngConstant.ORDER_VERIFY_TYPE.fail);
        verify.setCreateName(SessionUtils.getUser().getSysUser().getName());
        count = this.engWasteUserOrderVerifyMapper.insert(verify);
        if(count == 0){
            return ServerResponse.fail("操作失败");
        }

        return ServerResponse.ok("操作成功");
    }

    private ReentrantLock lock = new ReentrantLock();

    /**
     * 客户确认
     * @param orderCode
     * @return
     */
    @Override
    @Transactional
    public ServerResponse empConfirm(String orderCode) {
       try{
           lock.lock();
           EngWasteUserOrder order = this.engWasteOrderMapper.selectOne(EngWasteUserOrder.builder().orderCode(orderCode).build());

           if(!order.getStatus().equals(EngConstant.WASTE_ORDER_STATUS.EMP_CONFIRMED)){
               return ServerResponse.ok("操作成功");
           }

           // 获取openid
           String openId = order.getOpenId();

           // 修改订单的状态值
           int count = this.engWasteOrderMapper.updateStatusByOrderCode(orderCode,EngConstant.WASTE_ORDER_STATUS.FINISH_ORDER);
           if(count == 0){
               return ServerResponse.fail("操作失败");
           }

           //给eng_user_in_remain增加数据
           EngUserInRemain remain = new EngUserInRemain();
           remain.setOpenId(openId);
           remain.setCreateTime(new Date());
           remain.setAmount(order.getTotalPrice());
           remain.setType(EngConstant.IN_REMAIN_SOURCE.IN_REMAIN);
           int num = this.engUserInRemainMapper.insert(remain);
           if(num == 0){
               return ServerResponse.fail("操作失败");
           }

           // 给用户增加余额
           count = this.engUserMapper.addRemain(openId,order.getTotalPrice());
           if(count == 0){
               throw new GlobalException("操作失败!");
           }

           // 给业务员减倒掉余额
           // 首先判断业务员现在的余额是否能进行支付
           EngSysEmp emp = this.engSysEmpMapper.selectOne(EngSysEmp.builder().openId(order.getRecOpenId()).build());
//           if(emp.getRemain().doubleValue() < order.getTotalPrice().doubleValue()){
//               throw new GlobalException("当前业务员的账号余额不足");
//           }
           // 给当前的业务员减去余额
           count = this.engSysEmpMapper.updateRemain(emp.getOpenId(),order.getTotalPrice().negate());
           if(count == 0){
               throw new GlobalException("操作失败");
           }

           // 给用户增加积分
           // 获取对应的积分
           int score = this.scoreStrategy.sellScore(order.getTotalPrice());
           // 给对应的客户增加积分
           count = this.engUserMapper.addUserScore(openId, score);
           if(count == 0){
               throw new GlobalException("操作失败");
           }
           // 添加积分明细信息
           count = this.engInScoreMapper.insert(EngInScore.builder().openId(openId).num(score).type(EngConstant.IN_SCORE_SOURCE.SELL_SCORE).createTime(new Date()).build());
           if(count == 0){
               throw new GlobalException("操作失败");
           }


           // 批量新增库存信息和对库存总数的修改
           List<EngWasteUserOrderItem> orderItems = this.engWasteOrderItemMapper.selectList(new EntityWrapper<>(EngWasteUserOrderItem.builder().orderCode(order.getOrderCode()).build()));
           orderItems.forEach(e->{
               // 获取到typeId,实际上就是最后一个子类型的id.
               Integer typeId = null;
               if(e.getWasteTypeParam() != null){
                   typeId = Integer.parseInt(e.getWasteTypeParam());
               }else if(e.getWasteItemValue() != null){
                   typeId = Integer.parseInt(e.getWasteItemValue());
               }else if(e.getWasteType() != null){
                   typeId = e.getWasteType();
               }

               // 修改库存信息(增加库存)
               this.engWasteTypeTreeMapper.addStock(typeId,e.getTotalNum());

               // 然后追加一条明细信息
               EngStockDetail detail = new EngStockDetail();
               detail.setTypeId(typeId);
               detail.setCreateTime(new Date());
               detail.setPrice(e.getSinglePrice());
               detail.setNum(e.getTotalNum());
               detail.setType(EngConstant.STOCK_OPS_TYPE.COL_TYPE);
               this.engStockDetailMapper.insert(detail);

           });
           return ServerResponse.ok("操作成功");
       }finally {
           lock.unlock();
       }
    }

    @Override
    public Pager customerOrderCount(EngWasteOrderVO engWasteOrderVO) {
        return Pager.adapt(this.engWasteUserOrderMapper.customerOrderCount(engWasteOrderVO));
    }

    @Override
    public EngWasteOrderVO businessSummary(EngWasteOrderVO engWasteOrderVO) {
        return this.engWasteUserOrderMapper.businessSummary(engWasteOrderVO);
    }

    /**
     * 根据用户输入的值,自动联想到相似的值
     * @param openId
     * @param name
     * @return
     */
    @Override
    public ServerResponse AIInput(String openId, String name,String phone) {
        List<EngWasteOrderVO> result =  this.engWasteUserOrderMapper.AIInput(openId,name,phone);
        return ServerResponse.ok(result);
    }

    /**
     * 修改订单状态
     * @param orderCode
     * @param status
     * @return
     */
    private int updateOrderStatus(String orderCode,Integer status){
        return this.engWasteOrderMapper.updateOrderStatus(orderCode,status);
    }

}
